/**
 * @file uBlox.java
 *
 * Parse output messages from the Bluetooth receiver
 * 
 * Author: DKE Aerospace Germany GmbH
 *
 * Copyright 2011 European Commission
 *
 * Licensed under the EUPL, Version 1.1 only (the "Licence");
 * You may not use this work except in compliance with the
 * Licence.
 * You may obtain a copy of the Licence at:
 * http://ec.europa.eu/idabc/eupl
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 *
 **/
package com.dkeaerospace.egnosdemoapp;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
import eu.hydrologis.geopaparazzi.R;

/**
 * Class to Parse output messages from the Bluetooth receiver.
 **/
public class uBlox {
    private static final int BUFFER = 1000;
    private static final int CHKSUM_START_BYTE = 4;
    private static final int PAYLOAD_START_BYTE = 12;
    /** The following defines the uBlox specific synchronization identifiers. */
    private static final String HEADER_1 = "B5";
    private static final String HEADER_2 = "62";
    /** The following defines the uBlox specific class identifiers. */
    static final String CLASS_ACK = "05";
    static final String CLASS_AID = "0B";
    static final String CLASS_CFG = "06";
    static final String CLASS_ESF = "10";
    static final String CLASS_INF = "04";
    static final String CLASS_MON = "0A";
    static final String CLASS_NAV = "01";
    static final String CLASS_RXM = "02";
    static final String CLASS_TIM = "0D";

    /** The following defines the uBlox specific message identifiers. */
    static final String ID_ACK = "01";
    static final String ID_ALM = "30";
    static final String ID_EPH = "31";
    static final String ID_NAK = "00";
    static final String ID_POSLLH = "02";
    static final String ID_PRT = "00";
    static final String ID_RAW = "10";
    static final String ID_SBAS = "16";
    static final String ID_SFRB = "11";

    /** Definition of SISNeT Login details. */
    private static final String SISNET_USERNAME = "dkeaeros,";
    private static final String SISNET_PASSWORD = "Zz8pG51E\n";

    /** The following defines the uBlox specific payload lengths. */
    static final int LENGTH_HEADER = 6;
    static final int LENGTH_CHKSUM = 2;
    static final int LENGTH_PRT = 20;
    private static final int LENGTH_POLL_RAW = 0;
    private static final int LENGTH_POLL_SFRB = 0;
    private static final int LENGTH_POLL_EPH_ALL = 0;
    private static final int LENGTH_POLL_POSLLH = 0;
    private static final int LENGTH_POLL_EPH_SV = 1;
    static int LENGTH_EPH_ALL = 104;
    static int LENGTH_EPH_SV = 8;
    static int LENGTH_POSLLH = 28;
    static int LENGTH_RAW = 0;
    static final int LENGTH_SBAS = 8;
    static int LENGTH_SFRB = 42;
    static final int HEX_BASE = 16;
    private static final int HEX_ONE_DIGIT = (int) Math.pow(HEX_BASE, 1.0);
    private static final int HEX_TWO_DIGIT = (int) Math.pow(HEX_BASE, 2.0);
    private static final int HEX_THREE_DIGIT = (int) Math.pow(HEX_BASE, 3.0);
    static final int BIN_BASE = 2;
    private static GlobalState gs;
    Context context;
    FileWriter gpxwriter;
    FileWriter internalLogFilewriter;
    BufferedWriter out;
    static LogFiles log;
    private SfrbRawThread sfrbRawThread;
    private static final String TAG = "EGNOS-SDK";
    static String[] sSf = new String[4];
    static String ephemSubFrame;
    static double[][] sat_data = new double[12][4];
    static double[][] rxmRawD = new double[32][4];
    String msg1 = new String();
    String msg10 = new String();
    String msg12 = new String();
    String msg7 = new String();
    String msg6 = new String();
    String[] m18_t = new String[5];
    String[] m26_t = new String[25];
    String[] msg2_5 = new String[8];
    String[] msg24_t = new String[10];
    static String[] ephemData = new String[32];
    static String egnosSubframe;
    static String egnosMts;
    static int countEphem = 0;
    int countMsg2_t = 0;
    int countMsg3_t = 0;
    int countMsg24_t = 0;
    int countMsg18_t = 0;
    int countMsg26_t = 0;
    int countMsg18 = 0;
    int countMsg24 = 0;
    int countMsg26 = 0;
    static int positionCount = 0;
    private String s;
    String[] sviD = new String[12];
    private static int egnos;
    public static int sisnet;
    private static int sisnetSettings;
    private static int gps;
    private static int egnosSettings;
    private static int sisnetUnavailable;
    private static int egnosUnavailable;
    private static int gpsUnavailable;
    private static int sisUnavailable;
    static Handler messageHandler;
    static double[] currentPosition = new double[10];
    public static int startThread = 0;
    static GlobalState gsg;
    int countSVID = 0;

    /**
     * @author DKEITAdmin
     * 
     */

    /**
     * Load library for GPS-SW-Receiver Module.
     **/
    static {
        System.loadLibrary("GPSSWReceiver");
    }

    /**
     * getLongitudeLatitudeEGNOS function
     * Get EGNOS coordinates from SW receiver.
     * 
     * @param ephemData         32 X 1 table of Ephemeris Data.
     * @param sat_data          12X 4 table of Satellite Data.
     * @param msg1              Message 1.
     * @param msg10             Message 10.
     * @param msg12             Message 12.
     * @param msg7              Message 7.
     * @param msg6              Message 6.
     * @param m18_t             5 X 1 table of Message 18.
     * @param m26_t             25 X 1 table of Message 26.
     * @param msg2_5            8 X 1 table of Messages 2 to 5.
     * @param msg24_t           10 X 1 table of Messages 24.
     * @param initial_position  4 X 1 table of Initial Position.
     * @param username          username of SISNeT login.
     * @param password          password of SISNeT login.
     * @param egnos             egnos data availability.
     * @param sisnet            sisnet data availability.
     * @return coordinates      1 x 8 table of coordinates.
     **/
    private native double[] getLongitudeLatitudeEGNOS( String[] ephemData, double[][] sat_data, String msg1, String msg10,
            String msg12, String msg7, String msg6, String[] m18_t, String[] m26_t, String[] msg2_5, String[] msg24_t,
            double[] initial_position, String username, String password, int egnos, int sisnet );

    /**
     * getLongitudeLatitudeEGNOS function 
     * Get GPS coordinates from SW receiver.
     * 
     * @param ephemData         32 X 1 table of Ephemeris Data.
     * @param sat_data          12 X 4 table of Satellite Data.
     * @param initial_position  4 X 1 table of Initial Position.
     * @param username          username of SISNeT login.
     * @param password          password of SISNeT login.
     * @return coordinates      1 x 7 table of coordinates.
     **/
    private native double[] getLongitudeLatitudeGPS( String[] ephemData, double[][] sat_data, double[] initial_position,
            String username, String password );

    /**
     * checkSisnet function 
     * Checks if SISNeT is available or not.
     * 
     * @param username          username of SISNeT login.
     * @param password          password of SISNeT login.
     * @return connect          0 or -1 if SISNeT is available or not.
     **/
    private native int checkSisnet( final String username, final String password );

    /**
     * uBlox Constructor. 
     * Constructs a message handler and an interface to the
     * global information of the application that called uBlox class.
     * 
     * @param handler      handler to display messages on the UI.
     * @param context      interface to the global information of 
     *                     the application environment.
     **/
    public uBlox( Handler handler, Context context ) {
        this.context = context;
        uBlox.messageHandler = handler;
        gs = GlobalState.getInstance();
    }

    /**
     * uBlox Constructor. 
     * Constructs an interface to global information of the
     * application that called uBlox class.
     * 
     * @param context     interface to the global information of the application
     *                    environment.
     **/
    public uBlox( Context context ) {
        this.context = context;
        gs = GlobalState.getInstance();
    }

    /**
     * uBlox Constructor. 
     * Constructs an interface to global information of the
     * application that called uBlox class and writer that writes to a log file.
     * 
     * @param context    interface to the global information of the application
     *                   environment.
     * @param gpxwriter  writer to the File named gpxFile.
     * @param internalLogFilewriter   writer to the File named internalLogFile.
     **/
    public uBlox( final Context context, final FileWriter gpxwriter, final FileWriter internalLogFilewriter ) {
        this.context = context;
        this.gpxwriter = gpxwriter;
        gs = GlobalState.getInstance();
        log = new LogFiles(gpxwriter, internalLogFilewriter);
    }

    /**
     * init function. 
     * This function initializes the SFRbRawThread to buffer
     * messages from the Bluetooth receiver.
     **/
    public final void init() {
        GlobalState gS;
        int receiverType = 0;
        gS = BluetoothConnect.getGs();
        receiverType = BluetoothConnect.getReceiverType();
        switch( receiverType ) {
        case 1:
            if (gS.getSocket() != null) {
                sfrbRawThread = new SfrbRawThread();
                sfrbRawThread.start();
            } else {
                // Toast.makeText(gS.getBaseContext(), R.string.connectToReceiver,
                // Toast.LENGTH_SHORT).show();
                Log.e(TAG, "EDAM | Could not identify the globalstate.");
            }
            break;
        default:
            Log.d(TAG, "EDAM | No uBlox receiver.");
        }
    }

    /**
     * SfrbRawThread class. 
     * A thread to start writing and reading from the
     * Bluetooth receiver, Gets Ephemeris data, Satellite data, Raw data. 
     * Gets the GPS coordinates, EGNOS coordinates and Bluetooth Receiver 
     * coordinates.
     **/
    public class SfrbRawThread extends Thread {
        String sisnetusername, sisnetpassword;
        double[] coordinatesGPS = new double[8];
        double[] coordinatesEgnos = new double[9];
        double[] initialPosition = new double[]{0.0, 0.0, 0.0, 0.0};
        double HDOP = 0;
        public final void run() {
            if (requestEph(null) != 3) {
                try {
                    while( true && gs.getSocket() != null ) {

                        egnosSettings = GlobalState.getEgnos();
                        sisnetSettings = GlobalState.getSISNeT();
                        Log.d(TAG, "Egnos Settings|" + egnosSettings);
                        Log.d(TAG, "SISNeT Settings|" + sisnetSettings);

                        Log.d(TAG, "Sfrb & Raw |");

                        if (parseUbx(CLASS_NAV + ID_POSLLH) == -1) {
                            Log.e(TAG, "SfrbRawThread | Error in parseUbx for POSLLH.");
                        }

                        if (parseUbx(CLASS_RXM + ID_RAW) == -1) {
                            Log.e(TAG, "SfrbRawThread | Error in parseUbx for RAW.");
                        }

                        if (countSVID == 12)
                            countSVID = 0;
                        if (sat_data[0] != null) {
                            if (sat_data[countSVID][0] != 0.0) {
                                sviD[0] = String.valueOf(sat_data[countSVID][0]);
                                checkNewSVId();
                                requestEph(sviD);
                                countSVID++;
                            } else
                                countSVID = 0;
                        }

                        if (egnos == 1 && sisnet == 0) {
                            if (parseUbx(CLASS_RXM + ID_SFRB) == -1) {
                                Log.e(TAG, "SfrbRawThread | Error in parseUbx for SFRB.");
                            } else
                                parseEgnosMessage();
                        }

                        if (gps != 0) {
                            Log.d(TAG, "uBlox | Acquiring GPS position.");

                            coordinatesGPS = getLongitudeLatitudeGPS(ephemData, sat_data, initialPosition, SISNET_USERNAME,
                                    SISNET_PASSWORD);

                            Log.d(TAG, "uBlox | Coordinaates GPS: \nuBlox | GPS Latitude: " + coordinatesGPS[0]
                                    + "\nuBlox | GPS Longitude:" + coordinatesGPS[1] + "\nuBlox | GPS Altitude:"
                                    + coordinatesGPS[2]);

                            if (coordinatesGPS != null) {
                                HDOP = coordinatesGPS[7];
                                if (coordinatesGPS[3] != 0.0 && coordinatesGPS[4] != 0.0 && coordinatesGPS[5] != 0.0
                                        && coordinatesGPS[6] != 0.0 && (HDOP < 3 || HDOP != 0)) {
                                    initialPosition[0] = coordinatesGPS[3];
                                    initialPosition[1] = coordinatesGPS[4];
                                    initialPosition[2] = coordinatesGPS[5];
                                    initialPosition[3] = coordinatesGPS[6];
                                    GlobalState.setinitialPosition(initialPosition);
                                } else {
                                    initialPosition = GlobalState.getinitialPosition();
                                }

                                if (coordinatesGPS[0] >= -80.0 || coordinatesGPS[0] <= 80.0 || coordinatesGPS[1] <= 180.0
                                        || coordinatesGPS[1] >= -180.0) {
                                    currentPosition[0] = coordinatesGPS[0]; // GPS Latitude
                                    currentPosition[1] = coordinatesGPS[1]; // GPS Longitude
                                    currentPosition[2] = coordinatesGPS[2]; // GPS Altitude
                                }
                            }

                            Log.e(TAG, "count 1:" + msg1);
                            Log.e(TAG, "count 10:" + msg10);
                            Log.e(TAG, "count 12:" + msg12);
                            Log.e(TAG, "count 7:" + msg7);
                            Log.e(TAG, "count 2:" + countMsg2_t);
                            Log.e(TAG, "count 3:" + countMsg3_t);
                            Log.e(TAG, "count 24:" + countMsg24);
                            Log.e(TAG, "count 18:" + countMsg18);
                            Log.e(TAG, "count 26:" + countMsg26);

                            if (egnos != 0) {
                                if (sisnetSettings == 0) { // SISNeT is OFF in Settings, i.e.
                                    // Signal in Space only
                                    if (msg1 != null && msg10 != null && msg12 != null && msg7 != null && countMsg2_t >= 2
                                            && countMsg3_t >= 2 && countMsg24 >= 10 && countMsg18 >= 5 && countMsg26 >= 20) {
                                        Log.d(TAG, "uBlox | Acquiring EGNOS position from Signal in Space.");

                                        coordinatesEgnos = getLongitudeLatitudeEGNOS(ephemData, sat_data, msg1, msg10, msg12,
                                                msg7, msg6, m18_t, m26_t, msg2_5, msg24_t, initialPosition, SISNET_USERNAME,
                                                SISNET_PASSWORD, egnos, sisnet);
                                        HDOP = coordinatesEgnos[8];
                                        if (coordinatesEgnos[4] != 0.0 && coordinatesEgnos[5] != 0.0
                                                && coordinatesEgnos[6] != 0.0 && coordinatesEgnos[7] != 0.0
                                                && (HDOP < 3 || HDOP != 0)) {
                                            initialPosition[0] = coordinatesEgnos[4];
                                            initialPosition[1] = coordinatesEgnos[5];
                                            initialPosition[2] = coordinatesEgnos[6];
                                            initialPosition[3] = coordinatesEgnos[7];
                                            GlobalState.setinitialPosition(initialPosition);
                                        } else {
                                            initialPosition = GlobalState.getinitialPosition();
                                        }
                                    }
                                } else if (sisnetSettings == 1) { // SISNeT is ON in Settings
                                    if (sisnet == 1) { // SVID ! = 120 or 124, i.e. SV 120 or 120
                                        // or 124 not in view.
                                        if (GlobalState.getNetwork() == 1) {
                                            int connect = checkSisnet(SISNET_USERNAME, SISNET_PASSWORD);
                                            if (connect != -1) {
                                                if (sisnetUnavailable == 1) {
                                                    if (GlobalState.getisCurrent() || GlobalState.getisTracking())
                                                        displayMessage(R.string.sisnetAvailable);
                                                    Log.d(TAG, "uBlox | SISNeT is available.");
                                                    sisnetUnavailable = 0;
                                                }
                                                Log.d(TAG, "uBlox | Acquiring EGNOS position from SISNeT.");
                                                coordinatesEgnos = getLongitudeLatitudeEGNOS(ephemData, sat_data, msg1, msg10,
                                                        msg12, msg7, msg6, m18_t, m26_t, msg2_5, msg24_t, initialPosition,
                                                        SISNET_USERNAME, SISNET_PASSWORD, egnos, sisnet);
                                                HDOP = coordinatesEgnos[8];
                                                if (coordinatesEgnos[4] != 0.0 && coordinatesEgnos[5] != 0.0
                                                        && coordinatesEgnos[6] != 0.0 && coordinatesEgnos[7] != 0.0
                                                        && (HDOP < 3 || HDOP != 0)) {
                                                    initialPosition[0] = coordinatesEgnos[4];
                                                    initialPosition[1] = coordinatesEgnos[5];
                                                    initialPosition[2] = coordinatesEgnos[6];
                                                    initialPosition[3] = coordinatesEgnos[7];
                                                    GlobalState.setinitialPosition(initialPosition);
                                                } else {
                                                    initialPosition = GlobalState.getinitialPosition();
                                                }
                                            } else {
                                                if (sisnetUnavailable == 0) {
                                                    if (GlobalState.getisCurrent() || GlobalState.getisTracking())
                                                        displayMessage(R.string.sisnetUnAvailable);
                                                }
                                                sisnetUnavailable = 1;
                                                Log.e(TAG, "uBlox | SISNeT currently unavailable.");
                                            }
                                        } else {
                                            if (GlobalState.getisCurrent() || GlobalState.getisTracking())
                                                displayMessage(R.string.sisnetNoNetwork);
                                            Log.e(TAG, "uBlox | Unable to connect to SISNeT, network not" + " available.");
                                        }
                                    } else { // SVID == 120 or 124, i.e. SV 120 or 120 or 124 is
                                        // in view.
                                        /*if (msg1 != null && msg10 != null && msg12 != null
                                            && msg7 != null && countMsg2_t >= 2 && countMsg3_t >= 2
                                            && countMsg24 >= 10 && countMsg18 >= 5
                                            && countMsg26 >= 20)*/
                                        if (countMsg2_t >= 2 && countMsg3_t >= 2) {
                                            Log.d(TAG, "uBlox | Acquiring EGNOS position from Signal in Space.");

                                            coordinatesEgnos = getLongitudeLatitudeEGNOS(ephemData, sat_data, msg1, msg10, msg12,
                                                    msg7, msg6, m18_t, m26_t, msg2_5, msg24_t, initialPosition, SISNET_USERNAME,
                                                    SISNET_PASSWORD, egnos, sisnet);
                                            HDOP = coordinatesEgnos[8];
                                            if (coordinatesEgnos[4] != 0.0 && coordinatesEgnos[5] != 0.0
                                                    && coordinatesEgnos[6] != 0.0 && coordinatesEgnos[7] != 0.0
                                                    && (HDOP < 3 || HDOP != 0)) {
                                                initialPosition[0] = coordinatesEgnos[4];
                                                initialPosition[1] = coordinatesEgnos[5];
                                                initialPosition[2] = coordinatesEgnos[6];
                                                initialPosition[3] = coordinatesEgnos[7];
                                                GlobalState.setinitialPosition(initialPosition);
                                            } else {
                                                initialPosition = GlobalState.getinitialPosition();
                                            }
                                        }
                                    }
                                }
                                Log.d(TAG, "uBlox | Coordinaates EGNOS: \nuBlox | EGNOS Latitude: " + coordinatesEgnos[0]
                                        + "\nuBlox | EGNOS Longitude:" + coordinatesEgnos[1] + "\nuBlox | EGNOS Altitude:"
                                        + coordinatesEgnos[2] + "\nuBlox | HPL:" + coordinatesEgnos[3]);

                            } else {
                                coordinatesEgnos[0] = 0.0; // EGNOS Latitude
                                coordinatesEgnos[1] = 0.0; // EGNOS Longitude
                                coordinatesEgnos[2] = 0.0; // EGNOS Altitude
                                coordinatesEgnos[3] = 0.0;
                            }
                        }
                        if (coordinatesEgnos != null) {
                            if (coordinatesEgnos[0] >= -80.0 || coordinatesEgnos[0] <= 80.0 || coordinatesEgnos[1] <= 180.0
                                    || coordinatesEgnos[1] >= -180.0) {
                                currentPosition[3] = coordinatesEgnos[0]; // EGNOS Latitude
                                currentPosition[4] = coordinatesEgnos[1]; // EGNOS Longitude
                                currentPosition[5] = coordinatesEgnos[2]; // EGNOS Altitude
                                currentPosition[6] = coordinatesEgnos[3]; // HPL
                            }
                        }
                        for( int i = 0; i < coordinatesGPS.length; i++ ) {
                            coordinatesGPS[i] = 0.0;
                        }
                        for( int i = 0; i < coordinatesEgnos.length; i++ ) {
                            coordinatesEgnos[i] = 0.0;
                        }
                        GlobalState.setPosition(currentPosition);
                        if (GlobalState.getisLogFile() == 1)
                            log.logUBloxPositionToSdCard(currentPosition, egnos, sisnet, GlobalState.getNetwork());
                        else
                            Log.e(TAG, "uBlox | Unable to create log file");
                        startThread = 1;
                    }
                } catch (Exception e) {
                    Log.e(TAG, "uBlox | SfrbRawThread: " + e.getMessage());
                    gs.setSocket(null);
                }
            }
        }
    }

    /**
     * checkNewEphemeris function 
     * This functions checks if a new satellite vehicle
     * id occurred in Satellite Data.
     **/
    private void checkNewSVId() {
        double sat_dataprn;
        int countsviD = 1;
        for( int i = 0; i < sat_data.length; i++ ) {
            if (sat_data[i] != null && sat_data[i][0] != 0.0) {
                try {
                    sat_dataprn = sat_data[i][0];
                    if (!linearSearchrxmRawD(sat_dataprn)) {
                        sviD[countsviD] = String.valueOf(sat_dataprn);
                        countsviD++;
                    }
                } catch (Exception e) {
                    Log.e(TAG, "uBlox | checkNewSVId: " + e.getMessage());
                }
            }
        }

    }

    /**
     * linearSearch function 
     * This functions searchs through Ephemeris data table
     * if the satellite vehicle id exists or not.
     * 
     * @param prn          The pseudo random noise
     * @return newsvid     new satellite vehicle id.
     **/
    public static boolean linearSearchrxmRawD( double prn ) {
        double svInts;
        boolean newsvid = false;
        for( int i = 0; i < rxmRawD.length; i++ ) {
            if (rxmRawD[i] != null) {
                svInts = rxmRawD[i][0];
                if (svInts == prn)
                    newsvid = true;
            }
        }
        return newsvid;
    }

    /**
     * linearSearch function 
     * This functions searchs through Ephemeris data table
     * if the satellite vehicle id exists or not.
     * 
     * @param  prn         The pseudo random noise
     * @return newsvid     new satellite vehicle id.
     **/
    public static boolean linearSearch( double prn ) {
        double ephemprn;
        boolean newsvid = false;
        for( int j = 0; j < ephemData.length; j++ ) {
            if (ephemData[j] != null) {
                ephemprn = Double.parseDouble(ephemData[j].substring(0, 2));
                if (ephemprn == prn)
                    newsvid = true;
            }
        }
        return newsvid;
    }

    /**
     * parseEgnosMessage function 
     * This functions buffers messages from Bluetooth receiver. The following 
     * messages are buffered, Message 1, Message 10,Message 12, Message 7,
     * Message6, 5 X 1 table of Message 18, 25 X 1 table of Message 26, 
     * 8 X 1 table of Messages 2 to 5, 10 X 1 table of Messages 24.
     **/
    private void parseEgnosMessage() {
        int band_id, block_id;
        int band_id_current, block_id_current;
        int type;

        Log.d(TAG, "egnossubFrame:" + egnosSubframe);

        Log.d(TAG, "egnosMts:" + egnosMts);
        if (null != egnosSubframe) {
            switch( Integer.parseInt(egnosMts) ) {
            case 1:
                if (sat_data[0][1] != 0.0) {
                    msg1 = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 1:" + msg1);
                }
                break;
            case 12:
                if (sat_data[0][1] != 0.0) {
                    msg12 = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 12:" + msg12);
                }
                break;
            case 10:
                if (sat_data[0][1] != 0.0) {
                    msg10 = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 10:" + msg10);
                }
                break;
            case 7:
                if (sat_data[0][1] != 0.0) {
                    msg7 = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 7:" + msg7);
                }
                break;
            case 6:
                if (sat_data[0][1] != 0.0) {
                    msg6 = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 6:" + msg6);
                }
                break;
            case 2:
                if (msg2_5[0] != null) {
                    type = Utils.get_type(egnosSubframe);
                    if (type == 2) {
                        msg2_5[4] = msg2_5[0];
                        Log.d(TAG, "Message 2_1:" + msg2_5[4]);
                    }
                }
                if (sat_data[0][1] != 0.0) {
                    msg2_5[0] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 2_0:" + msg2_5[0]);
                    countMsg2_t++;
                }
                break;
            case 3:
                if (msg2_5[1] != null) {
                    type = Utils.get_type(egnosSubframe);
                    if (type == 3) {
                        msg2_5[5] = msg2_5[1];
                        Log.d(TAG, "Message 3_1:" + msg2_5[5]);
                    }
                }
                if (sat_data[0][1] != 0.0) {
                    msg2_5[1] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 3_0:" + msg2_5[1]);
                    countMsg3_t++;
                }
                break;
            case 4:
                if (msg2_5[2] != null) {
                    type = Utils.get_type(egnosSubframe);
                    if (type == 4) {
                        msg2_5[6] = msg2_5[2];
                        Log.d(TAG, "Message 4_1:" + msg2_5[6]);
                    }
                }
                if (sat_data[0][1] != 0.0) {
                    msg2_5[2] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 4_0:" + msg2_5[2]);
                }
                break;
            case 5:
                if (msg2_5[3] != null) {
                    type = Utils.get_type(egnosSubframe);
                    if (type == 5) {
                        msg2_5[7] = msg2_5[3];
                        Log.d(TAG, "Message 5_1:" + msg2_5[7]);
                    }
                }
                if (sat_data[0][1] != 0.0) {
                    msg2_5[3] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    Log.d(TAG, "Message 5_0:" + msg2_5[3]);
                }
                break;
            case 24:
                Log.d(TAG, "tow sat_data: " + sat_data[0][1]);
                if (countMsg24_t == 10)
                    countMsg24_t = 0;
                if (sat_data[0][1] != 0.0) {
                    msg24_t[countMsg24_t] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                    countMsg24_t++;
                    countMsg24++;
                }
                break;
            case 18:
                Log.d(TAG, "tow sat_data: " + sat_data[0][1]);
                if (countMsg18_t == 5)
                    countMsg18_t = 0;
                band_id = Utils.get_bandId18(String.valueOf((int) sat_data[0][1]) + egnosSubframe);
                Log.d(TAG, "new band_id 18: " + band_id);
                boolean m18Check = false;
                if (m18_t[0] == null) {
                    if (sat_data[0][1] != 0.0) {
                        m18_t[0] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                        countMsg18_t++;
                        countMsg18++;
                    }
                } else {
                    for( int i = 0; i < m18_t.length; i++ ) {
                        if (m18_t[i] != null) {
                            band_id_current = Utils.get_bandId18(m18_t[i]);
                            Log.d(TAG, "current band_id 18: " + band_id_current);
                            if (band_id == band_id_current) {
                                if (sat_data[0][1] != 0.0) {
                                    m18_t[i] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                                    m18Check = true;
                                }
                            }
                        }
                    }
                    if (m18Check == false) {
                        if (sat_data[0][1] != 0.0) {
                            m18_t[countMsg18_t] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                            countMsg18_t++;
                            countMsg18++;
                        }
                    }
                }
                break;
            case 26:
                Log.d(TAG, "tow sat_data: " + sat_data[0][1]);
                if (countMsg26_t == 25)
                    countMsg26_t = 0;
                band_id = Utils.get_bandId26(String.valueOf((int) sat_data[0][1]) + egnosSubframe);
                block_id = Utils.get_blockId26(String.valueOf((int) sat_data[0][1]) + egnosSubframe);
                boolean m26Check = false;
                if (m26_t[0] == null) {
                    if (sat_data[0][1] != 0.0) {
                        m26_t[0] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                        countMsg26_t++;
                        countMsg26++;
                    }
                } else {
                    for( int i = 0; i < m26_t.length; i++ ) {
                        if (m26_t[i] != null) {
                            band_id_current = Utils.get_bandId26(m26_t[i]);
                            block_id_current = Utils.get_blockId26(m26_t[i]);
                            if (band_id == band_id_current && block_id == block_id_current) {
                                if (sat_data[0][1] != 0.0) {
                                    m26_t[i] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                                    m26Check = true;
                                }
                            }
                        }
                    }
                    if (m26Check == false) {
                        if (sat_data[0][1] != 0.0) {
                            m26_t[countMsg26_t] = String.valueOf((int) sat_data[0][1]) + egnosSubframe;
                            countMsg26_t++;
                            countMsg26++;
                        }
                    }
                }
                break;
            }
        } else
            Log.d(TAG, "EGNOS subframe no data available");
    }

    /**
     * caclChkSum function 
     * Calculate the checksum for the uBlox message.
     * 
     * @param messageHex     Formated hex String.
     * @return chkSum        The messages' checksum.
     **/
    static String clalcChkSum( final String messageHex ) {
        // String payload = "";
        String length = "";
        String checkSum = "";
        short CK_A = 0, CK_B = 0;
        int payloadEnd = 0;

        // messageHex = "B5620600140001000000D008000000E100000300010000000000D89D";
        char[] output = new char[messageHex.length()];
        for( int i = 0; i < messageHex.length(); i++ ) {
            output[i] = messageHex.charAt(i);
        }
        length = Character.toString(output[11]) + Character.toString(output[10]) + Character.toString(output[8])
                + Character.toString(output[9]);
        int lengthPayload = Integer.parseInt(length, HEX_BASE);
        if (lengthPayload != 0) {
            /**
             * The payload end must account for the uBlox sync bytes (4), the class
             * and id bytes (4) as well as the length bytes -> 12.
             */
            payloadEnd = PAYLOAD_START_BYTE + (lengthPayload * 2);
        } else {
            payloadEnd = PAYLOAD_START_BYTE;
        }
        /** Do not consider the uBlox sync bytes -> i=4. */
        for( int i = CHKSUM_START_BYTE; i < payloadEnd; i++ ) {
            String out = (Character.toString(output[i]) + Character.toString(output[i + 1]));
            int outint = Integer.parseInt(out, HEX_BASE);
            CK_A = (short) ((CK_A + outint) & 0xFF);
            CK_B = (short) ((CK_B + CK_A) & 0xFF);
            i++;
        }
        if (CK_A < HEX_ONE_DIGIT) {
            checkSum = "0";
            checkSum = checkSum + Integer.toHexString(CK_A);
        } else {
            checkSum = Integer.toHexString(CK_A);
        }

        if (CK_B < HEX_ONE_DIGIT) {
            checkSum = checkSum + "0";
            checkSum = checkSum + Integer.toHexString(CK_B);
        } else {
            checkSum = checkSum + Integer.toHexString(CK_B);
        }

        // Log.d(TAG, "uBlox | checkSum: " + checkSum);
        return checkSum;
    }

    /**
     * identifyuBloxReceiver function 
     * This functions identifies the connected Bluetooth receiver.
     * 
     * @param gS             Common for all receivers.
     * @return messages      A matrix with parsed messages from the 
     *                       Bluetooth receiver.
     **/
    public static final boolean identifyuBloxReceiver( final GlobalState gS ) {
        /** The Buffer used to read from the BT receiver */
        byte[] receiverByte = new byte[BUFFER];
        int numBytesRead = 0;
        int n = 0;
        int l = 0;
        String completeMessage = "";
        Log.d(TAG, "uBlox | DEBUG identify uBlox Receiver().");

        gsg = BluetoothConnect.getGs();

        try {
            completeMessage = generateMessage(uBlox.CLASS_CFG + uBlox.ID_PRT);
            sendMessageToReceiver(completeMessage);
        } catch (Exception e) {
            Log.e(TAG, "uBlox | Write not successful. (" + e.getMessage() + ")");
            e.printStackTrace();
            return false;
        }

        /** Wait 500ms to get the BT input stream. */
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Log.e(TAG, "uBlox | ThrdSleep (" + e.getMessage() + ")");
            e.printStackTrace();
        }

        try {
            if (gS.getInputStream().available() != 0) {
                try {
                    numBytesRead = Receiver.readMessage(receiverByte);
                    n = 2 * numBytesRead;
                    char[] output = new char[n];

                    for( int k = 0; k < numBytesRead; k++ ) {
                        byte v = receiverByte[k];
                        int i = (v >> 4) & 0xf;
                        output[l++] = (char) (i >= 10 ? ('a' + i - 10) : ('0' + i));
                        i = v & 0xf;
                        output[l++] = (char) (i >= 10 ? ('a' + i - 10) : ('0' + i));
                    }
                    boolean blnResult = false;
                    for( int i = 0; i < output.length - 8; i += 8 ) {
                        char[] charArray1 = new char[]{output[i], output[i + 1], output[i + 2], output[i + 3]};
                        char[] charArray2 = new char[]{'b', '5', '6', '2'};
                        if (Arrays.equals(charArray1, charArray2)) {
                            char[] charArray3 = new char[]{output[i + 4], output[i + 5], output[i + 6], output[i + 7]};
                            char[] charArray4 = new char[]{'0', '5', '0', '1'};
                            if (Arrays.equals(charArray3, charArray4)) {
                                blnResult = true;
                                break;
                            } else {
                                blnResult = false;
                            }
                        } else {
                            blnResult = false;
                        }
                    }

                    if (blnResult) {
                        Log.d(TAG, "uBlox | uBlox ACK-ACJ found: 05:" + output[4] + output[5] + "|01:" + output[6] + output[7]);
                        return true;
                    }
                } catch (Exception e) {
                    Log.e(TAG, "uBlox | Receiver could not be identified. (" + e.getMessage() + ")");
                    e.printStackTrace();
                    return false;
                }
            } else {
                Log.e(TAG, "uBlox | No data available.");
                return false;
            }
        } catch (IOException e) {
            Log.e(TAG, "uBlox - identifyuBloxReceiver | No inputStream available. (" + e.getMessage() + ")");
            e.printStackTrace();
            return false;
        }
        return false;
    }

    /**
     * sendMessageToReceiver function 
     * Sends a message to receiver, depending on the identifier.
     * 
     * @param message      Message to be sent.
     **/
    protected static void sendMessageToReceiver( final String message ) {
        // Log.d(TAG, "uBlox |  sendMessageToReceiver(mT).");
        GlobalState gS;
        gS = BluetoothConnect.getGs();
        byte[] command = Utils.generateByteMessage(message);
        Utils.write(command, gS);
    }

    /**
     * generateMessage function
     * This messages retrieves a message number (also
     * called message type MT) and generates the according message (incl. the
     * checksum).
     * 
     * @param mT         The message to be generated.
     * @return message   The generated message.
     */
    static final String generateMessage( final String mT ) {
        String message = "";
        String payload = "";
        String checkSum = "";
        int length;
        // Log.d(TAG, "uBlox | generateMessage().");

        if (mT == (CLASS_RXM + ID_SFRB)) {
            length = LENGTH_POLL_SFRB;
            payload = "";
            message = HEADER_1 + HEADER_2 + CLASS_RXM + ID_SFRB + calcMessageLength(length) + payload;
            checkSum = clalcChkSum(message);
            message = message + checkSum;
        } else if (mT == (CLASS_RXM + ID_RAW)) {
            length = LENGTH_POLL_RAW;
            payload = "";
            message = HEADER_1 + HEADER_2 + CLASS_RXM + ID_RAW + calcMessageLength(length) + payload;
            checkSum = clalcChkSum(message);
            message = message + checkSum;
        } else if (mT == (CLASS_RXM + ID_EPH)) {
            length = LENGTH_POLL_EPH_ALL;
            payload = "";
            message = HEADER_1 + HEADER_2

            + CLASS_RXM + ID_EPH + calcMessageLength(length) + payload;
            checkSum = clalcChkSum(message);
            message = message + checkSum;
        } else if (mT == (CLASS_CFG + ID_SBAS)) {
            length = LENGTH_SBAS;
            payload = "0100010051080000";
            message = HEADER_1 + HEADER_2 + CLASS_CFG + ID_SBAS + calcMessageLength(length) + payload;
            checkSum = clalcChkSum(message);
            message = message + checkSum;
        } else if (mT == (CLASS_CFG + ID_PRT)) {
            length = LENGTH_PRT;
            payload = "01000000D008000000E100000300010000000000";
            message = HEADER_1 + HEADER_2 + CLASS_CFG + ID_PRT + calcMessageLength(length) + payload;
            checkSum = clalcChkSum(message);
            message = message + checkSum;
        } else if (mT == (CLASS_NAV + ID_POSLLH)) {
            length = LENGTH_POLL_POSLLH;
            payload = "";
            message = HEADER_1 + HEADER_2 + CLASS_NAV + ID_POSLLH + calcMessageLength(length) + payload;
            checkSum = clalcChkSum(message);
            message = message + checkSum;
        }
        // Log.d(TAG, "uBlox | Generated message: " + message);
        return message;
    }

    /**
     * generateMessageEphSv function
     * Generate message for Ephemeris.
     * 
     * @param mT         The message to be generated.
     * @param svId       The message to be generated.
     * @return message   The generated message.
     */
    static final String generateMessageEphSv( final String mT, final String svId ) {
        String message = "";
        String payload = "";
        String checkSum = "";
        int length = 0;
        // Log.d(TAG, "uBlox | generateMessage().");
        if (mT == (CLASS_RXM + ID_EPH)) {
            length = LENGTH_POLL_EPH_SV;
            payload = svId;
            message = HEADER_1 + HEADER_2 + CLASS_RXM + ID_EPH + calcMessageLength(length) + payload;
            checkSum = clalcChkSum(message);
            message = message + checkSum;
        }
        // Log.d(TAG, "uBlox | Generated message: " + message);
        return message;
    }

    /**
     * calcMessageLength function 
     * Calculate the messages' length.
     * 
     * @param length         The message to be generated.
     * @return lenghtBytes   The generated message.
     */
    static final String calcMessageLength( final int length ) {
        String lengthBytes = "0000";
        if (length < HEX_ONE_DIGIT) {
            lengthBytes = "0";
            lengthBytes = lengthBytes + Integer.toHexString(length);
            lengthBytes = lengthBytes + "00";
        } else if (length > HEX_ONE_DIGIT && length < HEX_TWO_DIGIT) {
            lengthBytes = Integer.toHexString(length);
            lengthBytes = lengthBytes + "00";
        } else if (length > HEX_TWO_DIGIT && length < HEX_THREE_DIGIT) {
            lengthBytes = lengthBytes + "0";
            lengthBytes = Integer.toHexString(length);
        } else {
            lengthBytes = Integer.toHexString(length);
        }
        return lengthBytes;
    }

    /**
     * readSfrb function 
     * This function parses and stores the Sfrb messages.
     * Also logs the Egnos Mts and Egnos Subframe messages to a log file.
     * 
     * @param   message        The message to be parsed from the receiver.
     * @param   lengthHeader   The length of the message.
     * @return  errorNum       The variable provides information about the 
     *                         correct execution (1) or not (-1).
     */
    static final int readSfrb( char[] message, int lengthHeader ) {
        byte[] receiverByte = new byte[BUFFER];
        byte[] receiverByteHeader = new byte[6];
        char[] expectedBytesSfrb = new char[]{'0', '0', '0', '0'};

        char[] output = new char[50];
        char[] msgPaylChkSum = new char[500];
        int numBytesRead = 0;
        int expectedLengthSfrb = 0;

        int h = 12;
        int numSvInt = 0;
        int lengthCharArray = 0;
        int chn = 0;
        int svId = 0;

        StringBuffer receiverMessage = new StringBuffer("");

        // Log.d(TAG, "uBlox | parseUbx().");
        expectedLengthSfrb = LENGTH_HEADER + LENGTH_SFRB + LENGTH_CHKSUM;
        expectedBytesSfrb = new char[]{'0', '2', '1', '1'};

        String rxmSfrb = CLASS_RXM + ID_SFRB;

        int msglength = 0;

        // Log.d(TAG, "uBlox | Identified: " + id);
        String numSvfLength = Utils.charToStringUbl(message, 8, 11);
        int msgLenInt = 0;
        try {
            msgLenInt = Integer.parseInt(numSvfLength, HEX_BASE);
        } catch (Exception e) {
            numSvInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            output = null;
            return -1;
        }
        LENGTH_SFRB = msgLenInt;
        msglength = LENGTH_SFRB + LENGTH_CHKSUM;
        byte[] receiverByteSfrb = new byte[msglength];
        lengthCharArray = msglength * 2;
        msgPaylChkSum = new char[lengthCharArray];
        msgPaylChkSum = Utils.toHexCharArray(receiverByteSfrb);
        char[] recv = new char[]{message[4], message[5], message[6], message[7]};
        boolean blnResult = Arrays.equals(expectedBytesSfrb, recv);
        if (blnResult) {
            receiverMessage.append(Utils.toHex(receiverByteSfrb));
            int msgLen = (LENGTH_HEADER + msglength) * 2;
            output = new char[msgLen];
            System.arraycopy(message, 0, output, 0, msgLen);

            // System.arraycopy(msgPaylChkSum, 0, output, lengthHeader,
            // lengthCharArray);
            // Log.d(TAG, "---> id: " + id + ", msgLeng: " + msgLenInt
            // + ", length: " + output.length);
        } else {
            output = null;
            Log.d(TAG, "uBlox | Msg could not be identified.");
        }
        Log.i(TAG, "uBlox | output readSfrb :" + String.valueOf(output));
        String mT = Utils.charToString(output, 0, 7);
        String rxmsfrb = HEADER_1 + HEADER_2 + CLASS_RXM + ID_SFRB;
        Log.d(TAG, "uBlox | rxmsfrb " + rxmsfrb);
        GlobalState.setMctSfrb();
        Log.d(TAG, GlobalState.getMct() + " | SFRB-MT: " + mT);
        // Log.d(TAG, "SFRB-MT: " + mT);
        String chnS = Character.toString(output[h + 0]) + Character.toString(output[h + 1]);
        try {
            chn = Integer.parseInt(chnS, HEX_BASE);
            chnS = (Integer.valueOf(chn)).toString();
        } catch (Exception e) {
            chn = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            chnS = null;
        }

        String svIdS = Character.toString(output[h + 2]) + Character.toString(output[h + 3]);
        try {
            svId = Integer.parseInt(svIdS, HEX_BASE);
            svIdS = (Integer.valueOf(svId)).toString();
            Log.d(TAG, "uBlox | svID: " + svIdS);
            GlobalState.setSVId(svId);
        } catch (Exception e) {
            svId = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            svIdS = null;
        }

        char[] preamble = new char[8];
        char[] egnosMt = new char[6];
        /** The EGNOS subframe. */
        char[] egnosSf = new char[250];
        char[] egnosSfTrunc = new char[250];
        char[] payload = new char[212];
        char[] parity = new char[24];
        if (svId == 120 || svId == 124) {
            String dwordS = "", dwordB = "", dwordAll = "", egnosSfComplete = "";
            for( int i = 0; i < 8; i++ ) {
                dwordS = Utils.charToStringUbl(output, (h + 4 + 8 * i), (h + 11 + 8 * i));
                dwordAll = dwordAll + dwordS;
                long dwordLong = Long.parseLong(dwordS, HEX_BASE);
                dwordB = Long.toBinaryString(dwordLong);
                while( dwordB.length() < 32 ) {
                    dwordB = "0" + dwordB;
                }
                egnosSfComplete = egnosSfComplete + dwordB;
            }

            egnosSf = egnosSfComplete.toCharArray();
            System.arraycopy(egnosSf, 0, preamble, 0, 8);
            System.arraycopy(egnosSf, 8, egnosMt, 0, 6);
            System.arraycopy(egnosSf, 14, payload, 0, 212);
            System.arraycopy(egnosSf, 226, parity, 0, 24);

            System.arraycopy(preamble, 0, egnosSfTrunc, 0, 8);
            System.arraycopy(egnosMt, 0, egnosSfTrunc, 8, 6);
            System.arraycopy(payload, 0, egnosSfTrunc, 14, 212);
            System.arraycopy(parity, 0, egnosSfTrunc, 226, 24);

            String egnosMtS = new String(egnosMt);
            int egnosMtI = Integer.parseInt(egnosMtS, 2);
            egnosMts = (new Integer(egnosMtI)).toString();
            String preambleS = new String(preamble);
            String payloadS = new String(payload);
            String parityS = new String(parity);
            egnosSubframe = preambleS + egnosMtS + payloadS + parityS;
            if (GlobalState.getisLogFile() == 1)
                log.logEgnosToSdCard(egnosMts, egnosSubframe);
            else
                Log.e(TAG, "uBlox | Unable to create log file");
        }
        return 1;
    }

    /**
     * readRaw function 
     * This function parses and stores the Raw messages.
     * Also logs the satellite data messages to a log file.
     * 
     * @param   message        The message to be parsed from the receiver.
     * @param   lengthHeader   The length of the message.
     * @return  errorNum       The variable provides information about the 
     *                         correct execution (1) or not (-1).
     */
    static final int readRaw( char[] message, int lengthHeader ) {
        char[] expectedBytesRaw = new char[]{'0', '0', '0', '0'};
        char[] output = new char[50];
        byte[] receiverByte = new byte[BUFFER];
        char[] msgPaylChkSum = new char[500];
        int expectedLengthRaw = 0;
        int numSvInt = 0;
        int lengthCharArray = 0;
        int h = 12;
        int msglength = 0;
        int numBytesRead = 0;
        StringBuffer receiverMessage = new StringBuffer("");
        int chn = 0;
        int svId = 0;
        double iTowLong = 0;
        int weekInt = 0;
        double cpDoubleValue = 0;
        double prDoubleValue = 0;
        long domLong = 0;
        int svInt = 0;
        int iTow = 0;
        int qiInt = 0;
        int cnInt = 0;
        int lliInt = 0;
        int countSat_data = 0;
        boolean svidCheck = false;

        String numSvfLength = Utils.charToStringUbl(message, 8, 11);

        expectedLengthRaw = LENGTH_HEADER + LENGTH_RAW + LENGTH_CHKSUM;
        expectedBytesRaw = new char[]{'0', '2', '1', '0'};
        String rxmRaw = CLASS_RXM + ID_RAW;

        int msgLenInt = 0;

        try {
            msgLenInt = Integer.parseInt(numSvfLength, HEX_BASE);
            numSvInt = (msgLenInt - 8) / 24;
        } catch (Exception e) {
            numSvInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            output = null;
            return -1;
        }
        LENGTH_RAW = msgLenInt;
        msglength = LENGTH_RAW + LENGTH_CHKSUM;
        byte[] receiverByteRaw = new byte[msglength];
        lengthCharArray = numBytesRead * 2;
        msgPaylChkSum = new char[lengthCharArray];
        msgPaylChkSum = Utils.toHexCharArray(receiverByteRaw);
        char[] recv = new char[]{message[4], message[5], message[6], message[7]};
        boolean blnResult = Arrays.equals(expectedBytesRaw, recv);
        if (blnResult) {
            receiverMessage.append(Utils.toHex(receiverByte));
            int msgLen = (LENGTH_HEADER + msglength) * 2;
            output = new char[msgLen];
            System.arraycopy(message, 0, output, 0, msgLen);
            // Log.d(TAG, "---> id: " + id + ", msgLeng: " + msgLenInt
            // + ", length: " + output.length);
        } else {
            output = null;
            Log.d(TAG, "uBlox | Msg could not be identified.");
        }
        Log.i(TAG, "uBlox | output readRaw :" + String.valueOf(output));

        String mT = Utils.charToString(output, 0, 7);
        String rxmraw = HEADER_1 + HEADER_2 + CLASS_RXM + ID_RAW;

        Log.d(TAG, "uBlox | rxmraw " + rxmraw);
        for( int i = 0; i < 12; i++ ) {
            for( int j = 0; j < 4; j++ ) {
                sat_data[i][j] = 0.0;
            }
        }
        GlobalState.setMctRaw();
        Log.d(TAG, GlobalState.getMct() + " | RAW-MT: " + mT);
        String siTow = Utils.charToStringUbl(output, h + 0, h + 7);
        Log.d(TAG, " | iTow: " + siTow);
        try {
            iTowLong = Long.parseLong(siTow, HEX_BASE);
            Log.d(TAG, " | iTowLong: " + iTowLong);
            iTowLong = iTowLong / 1000;
        } catch (Exception e) {
            iTowLong = 0;
            // Log.e(TAG, "EDAM | " + e.getMessage());
        }

        String week = Utils.charToStringUbl(output, h + 8, h + 11);
        try {
            weekInt = Integer.parseInt(week, HEX_BASE);
        } catch (Exception e) {
            weekInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
        }

        String numSv = Character.toString(output[h + 12]) + Character.toString(output[h + 13]);
        try {
            numSvInt = Integer.parseInt(numSv, HEX_BASE);
        } catch (Exception e) {
            numSvInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
        }

        for( int i = 0; i < numSvInt; i++ ) {
            String cp = Utils.charToStringUbl(output, (h + 16 + 48 * i), (h + 31 + 48 * i));

            try {
                long cpLongBits = Long.valueOf(cp, HEX_BASE).longValue();
                cpDoubleValue = Double.longBitsToDouble(cpLongBits);
            } catch (Exception e) {
                cpDoubleValue = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            }

            String pr = Utils.charToStringUbl(output, (h + 32 + 48 * i), (h + 47 + 48 * i));
            try {
                long prLongBits = Long.valueOf(pr, HEX_BASE).longValue();
                prDoubleValue = Double.longBitsToDouble(prLongBits);
            } catch (Exception e) {
                prDoubleValue = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            }

            String dom = Utils.charToStringUbl(output, (h + 48 + 48 * i), (h + 55 + 48 * i));
            try {
                domLong = new BigInteger(dom, HEX_BASE).longValue();
            } catch (Exception e) {
                domLong = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            }

            String sv = Character.toString(output[h + 56 + 48 * i]) + Character.toString(output[h + 57 + 48 * i]);
            try {
                svInt = Integer.parseInt(sv, HEX_BASE);
            } catch (Exception e) {
                svInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            }
            if (svInt == 120 || svInt == 124)
                svidCheck = true;

            String mesQi = Character.toString(output[h + 58 + 48 * i]) + Character.toString(output[h + 59 + 48 * i]);
            try {
                qiInt = Integer.parseInt(mesQi, HEX_BASE);
            } catch (Exception e) {
                qiInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            }
            String cn = Character.toString(output[h + 60 + 48 * i]) + Character.toString(output[h + 61 + 48 * i]);
            try {
                cnInt = Integer.parseInt(cn, HEX_BASE);
            } catch (Exception e) {
                cnInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            }
            String lli = Character.toString(output[h + 62 + 48 * i]) + Character.toString(output[h + 63 + 48 * i]);
            try {
                lliInt = Integer.parseInt(lli, HEX_BASE);
            } catch (Exception e) {
                lliInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            }

            if (svInt <= 32 && linearSearch((double) svInt)) {
                rxmRawD[i][0] = (double) svInt;
                rxmRawD[i][1] = (double) iTowLong;
                rxmRawD[i][2] = prDoubleValue;
                rxmRawD[i][3] = (double) cnInt;
            }

            if (svInt <= 32 && linearSearch((double) svInt)) {
                sat_data[countSat_data][0] = (double) svInt;
                sat_data[countSat_data][1] = (double) iTowLong;
                sat_data[countSat_data][2] = prDoubleValue;
                sat_data[countSat_data][3] = (double) cnInt;
                Log.d(TAG, "Sat_Data:" + sat_data[countSat_data][0] + sat_data[countSat_data][1] + ","
                        + sat_data[countSat_data][2] + "," + sat_data[countSat_data][3]);
                countSat_data++;
            }
        }

        Log.d(TAG, "numSVInt: " + numSvInt);
        if (numSvInt < 4) { // numSVInt < 4
            gps = 0;
            if (gpsUnavailable == 0)
                displayMessage(R.string.gpsUnAvailable);
            gpsUnavailable = 1;
            egnos = 0;
        } else { // numSVInt >= 4
            gps = 1;
            gpsUnavailable = 0;
            if (svidCheck && numSvInt >= 5) { // SVID = 120 or 124 and numSVInt > = 5
                egnos = 1;
                sisnet = 0;
                egnosUnavailable = 0;
                sisUnavailable = 0;
            } else if (!svidCheck && numSvInt >= 5) { // SVID ! = 120 or 124 and
                                                      // numSVInt>=5
                gps = 1;
                sisnet = 1;
                if (egnosSettings == 1)
                    egnos = 1;
                egnosUnavailable = 0;
                Log.d(TAG, "SV ID 120 or 124 not available switch to SISNeT: " + sisnet);
                if (sisnetSettings == 0) {
                    if (GlobalState.getisCurrent() || GlobalState.getisTracking() && (sisnet == 1 && egnosSettings == 1)) {
                        Log.d(TAG, "am here: " + sisnet + sisnetSettings);
                        if (sisUnavailable == 0)
                            displayMessage(R.string.signalinSpaceUnavailable);
                        sisUnavailable = 1;
                    }
                }
            } else if (!svidCheck && numSvInt < 5) { // SVID ! = 120 or 124 and
                                                     // numSVInt < 5
                egnos = 0;
                Log.d(TAG, "numSV < 5, EGNOS not available: " + egnos);
                if (GlobalState.getisCurrent() || GlobalState.getisTracking() && egnosSettings == 1) {
                    if (egnosUnavailable == 0)
                        displayMessage(R.string.egnosUnAvailable);
                    egnosUnavailable = 1;
                }
            }
        }
        Log.d(TAG, "gps|" + gps);
        Log.d(TAG, "egnos|" + egnos);
        Log.d(TAG, "sisnet|" + sisnet);

        if (GlobalState.getisLogFile() == 1)
            log.logRawToSdCard(" SV | iTow    | Pseudorange          | SNR");
        else
            Log.e(TAG, "uBlox | Unable to create log file");
        for( int j = 0; j < numSvInt; j++ ) {
            String rxmRawS = null;
            if (rxmRawD[j] != null) {
                rxmRawS = (Double.valueOf(rxmRawD[j][0])).toString() + " | " + (Double.valueOf(rxmRawD[j][1])).toString() + " | "
                        + (Double.valueOf(rxmRawD[j][2])).toString() + " | " + (Double.valueOf(rxmRawD[j][3])).toString();
                // Log.d(TAG, rxmRawS);
            }
            if (GlobalState.getisLogFile() == 1)
                log.logRawToSdCard(rxmRawS);
            else
                Log.e(TAG, "uBlox | Unable to create log file");
        }
        return 1;
    }

    /**
     * readPosllh function 
     * This function parses and stores the Posllh messages.
     * Also logs the receiver coordinates to a log file.
     * 
     * @param   message        The message to be parsed from the receiver.
     * @param   lengthHeader   The length of the message.
     * @return  errorNum       The variable provides information about the 
     *                         correct execution (1) or not (-1).
     */
    static final int readPosllh( char[] message, int lengthHeader ) {
        char[] expectedBytesPosllh = new char[]{'0', '0', '0', '0'};
        char[] output = new char[50];
        char[] msgPaylChkSum = new char[500];
        int expectedLengthPosllh = 0;
        int numSvInt = 0;
        int lengthCharArray = 0;
        int msglength = 0;
        int numBytesRead = 0;
        StringBuffer receiverMessage = new StringBuffer("");
        int iTow = 0;
        int h = 12;

        String numSvfLength = Utils.charToStringUbl(message, 8, 11);
        expectedLengthPosllh = LENGTH_HEADER + LENGTH_POSLLH + LENGTH_CHKSUM;
        expectedBytesPosllh = new char[]{'0', '1', '0', '2'};
        String navPll = CLASS_NAV + ID_POSLLH;

        int msgLenInt = 0;
        try {
            msgLenInt = Integer.parseInt(numSvfLength, HEX_BASE);
        } catch (Exception e) {
            numSvInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            output = null;
            return -1;
        }
        LENGTH_POSLLH = msgLenInt;
        msglength = LENGTH_POSLLH + LENGTH_CHKSUM;
        byte[] receiverBytePosllh = new byte[msglength];

        lengthCharArray = msglength * 2;
        msgPaylChkSum = new char[lengthCharArray];
        msgPaylChkSum = Utils.toHexCharArray(receiverBytePosllh);

        char[] recv = new char[]{message[4], message[5], message[6], message[7]};
        boolean blnResult = Arrays.equals(expectedBytesPosllh, recv);
        if (blnResult) {
            receiverMessage.append(Utils.toHex(receiverBytePosllh));
            int msgLen = (LENGTH_HEADER + msglength) * 2;
            output = new char[msgLen];
            System.arraycopy(message, 0, output, 0, msgLen);
        } else
            output = null;

        Log.i(TAG, "uBlox | output readPosllh :" + String.valueOf(output));
        Log.d(TAG, "uBlox | navPosllh " + navPll);
        String mT = Utils.charToString(output, 0, 7);
        String navPosllh = HEADER_1 + HEADER_2 + CLASS_NAV + ID_POSLLH;
        String siTow = Utils.charToStringUbl(output, h + 0, h + 7);
        try {
            iTow = Integer.parseInt(siTow, HEX_BASE);
            siTow = (Integer.valueOf(iTow)).toString();
        } catch (Exception e) {
            iTow = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            siTow = null;
        }

        String sLon = Utils.charToStringUbl(output, h + 8, h + 15);
        try {
            int Lon = Integer.parseInt(sLon, HEX_BASE);
            currentPosition[8] = (double) (Integer.valueOf(Lon)) * 1E-7;
        } catch (Exception e) {
            int Lon = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            sLon = null;
        }

        String sLat = Utils.charToStringUbl(output, h + 16, h + 23);
        try {
            int Lat = Integer.parseInt(sLat, HEX_BASE);
            currentPosition[7] = (double) (Integer.valueOf(Lat)) * 1E-7;
        } catch (Exception e) {
            int Lat = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            sLat = null;
        }

        String sHeight = Utils.charToStringUbl(output, h + 24, h + 31);
        try {
            int height = Integer.parseInt(sHeight, HEX_BASE);
            currentPosition[9] = (double) (Integer.valueOf(height)) * 1e-3;
        } catch (Exception e) {
            int height = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            sHeight = null;
        }

        String shMsl = Utils.charToStringUbl(output, h + 32, h + 39);
        try {
            int hMsl = Integer.parseInt(shMsl, HEX_BASE);
            shMsl = (Integer.valueOf(hMsl)).toString();
        } catch (Exception e) {
            int hMsl = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            shMsl = null;
        }

        String shAcc = Utils.charToStringUbl(output, h + 40, h + 47);
        try {
            int hAcc = Integer.parseInt(shAcc, HEX_BASE);
            shAcc = (Integer.valueOf(hAcc)).toString();
        } catch (Exception e) {
            int hAcc = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            shAcc = null;
        }

        String svAcc = Utils.charToStringUbl(output, h + 48, h + 55);
        try {
            int vAcc = Integer.parseInt(svAcc, HEX_BASE);
            svAcc = (Integer.valueOf(vAcc)).toString();
        } catch (Exception e) {
            int vAcc = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
            svAcc = null;
        }
        return 1;
    }

    /**
     * parseUbx function 
     * The function sends messages to receiver to get Ubx messages. 
     *  
     * @return errorNum     The variable provides information about the correct
     *                      execution (1) or not (-1).
     **/
    static final int parseUbx( String ClassId ) {
        String completeMessage = "";

        completeMessage = generateMessage(ClassId);
        sendMessageToReceiver(completeMessage);
        /** Wait 500ms to get the BT input stream. */
        try {
            Thread.sleep(900);
        } catch (InterruptedException e) {
            Log.e(TAG, "uBlox | ThrdSleep (" + e.getMessage() + ")");
            e.printStackTrace();
        }
        // reads and parses the message received.
        parseHeader();
        return 1;
    }

    /**
     * requestEph function 
     * The function requests for Ephemeris messages.
     * This function requests Ephemeris messages for any new satellite vehicle 
     * id in view, and also updates the Ephemeris data for any satellites 
     * already in view.
     * 
     * @param  newsvId     array of new or old Satellite Vehicle ids. 
     * @return errorNum    The variable provides information about the correct
     *                     execution (1) or not (-1).
     **/
    static final int requestEph( String[] newsvId ) {
        String completeMessage = "";
        String svId = "";

        if (newsvId != null) {
            for( int i = 0; i < newsvId.length; i++ ) {
                if (newsvId[i] != null) {
                    if ((int) Double.parseDouble(newsvId[i]) < 16)
                        svId = "0" + Integer.toHexString((int) Double.parseDouble(newsvId[i]));
                    else
                        svId = Integer.toHexString((int) Double.parseDouble(newsvId[i]));

                    completeMessage = generateMessageEphSv(CLASS_RXM + ID_EPH, svId);
                    sendMessageToReceiver(completeMessage);
                    /** Wait 500ms to get the BT input stream. */
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        Log.e(TAG, "uBlox | ThrdSleep (" + e.getMessage() + ")");
                        e.printStackTrace();
                    }
                    // reads and parses the message received.
                    parseHeader();
                }
            }
        } else {
            for( int i = 1; i < 33; i++ ) {
                if (i < 16)
                    svId = "0" + Integer.toHexString(i);
                else
                    svId = Integer.toHexString(i);
                completeMessage = generateMessageEphSv(CLASS_RXM + ID_EPH, svId);
                Log.e(TAG, "uBlox | completeMessage :" + completeMessage);
                sendMessageToReceiver(completeMessage);
                /** Wait 500ms to get the BT input stream. */
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Log.e(TAG, "uBlox | ThrdSleep (" + e.getMessage() + ")");
                    e.printStackTrace();
                }
                // reads and parses the message received.
                parseHeader();
            }
        }
        return 1;
    }

    /**
     * parseHeader function 
     * The function reads messages from the Bluetooth receiver and parses 
     * the messages based on the type of the message.
     * 
     * @return errorNum    The variable provides information about the correct
     *                     execution (1) or not (-1).
     **/
    static final void parseHeader() {
        byte[] receiverByteHeader = new byte[1000];
        byte[] byteRead = new byte[1000];
        char[] msgHeader_ = new char[500];
        char[] msgHeader = new char[500];
        int numBytesRead = 0;
        int lengthHeader = 0;
        String rxmEph = CLASS_RXM + ID_EPH;
        String rxmraw = CLASS_RXM + ID_RAW;
        String rxmsfrb = CLASS_RXM + ID_SFRB;
        String navPosllh = CLASS_NAV + ID_POSLLH;
        char[] output = new char[50];
        String id = "";

        if (gs.getSocket() != null) {
            numBytesRead = Receiver.getNumBytes(receiverByteHeader);
            if (numBytesRead != 0) {
                if (numBytesRead >= LENGTH_HEADER) {
                    lengthHeader = numBytesRead * 2;
                    msgHeader = new char[lengthHeader];
                    msgHeader = Utils.toHexCharArray(receiverByteHeader);
                    Log.i(TAG, "uBlox | Message header All : " + String.valueOf(msgHeader));
                    id = Utils.charToString(msgHeader, 4, 7);
                    Log.i(TAG, "uBlox | ID to be parsed: " + id);

                    if (id.compareTo(rxmEph) == 0) { // 0231
                        parseEphSv(msgHeader, lengthHeader);
                    } else if (id.compareTo(rxmsfrb) == 0) { // 0211
                        readSfrb(msgHeader, lengthHeader);
                    } else if (id.compareTo(rxmraw) == 0) { // 0210
                        readRaw(msgHeader, lengthHeader);
                    } else if (id.compareTo(navPosllh) == 0) { // 0102
                        readPosllh(msgHeader, lengthHeader);
                    }
                } else
                    output = null;
            } else
                output = null;
        } else
            output = null;
    }

    /**
     * parseEphSv function 
     * The function parses the Ephemeris data.
     * 
     * @return errorNum     The variable provides information about the correct
     *                      execution (1) or not (-1).
     **/
    static final int parseEphSv( char[] message, int lengthHeader ) {
        char[] ephHeader = new char[]{'0', '0', '0', '0'};
        char[] output;
        char[] msgEph = new char[500];
        int numBytesRead = 0;
        int h = 12;
        int numSvInt = 0;
        int msgEphLen = 0;
        int msglength = 0;
        int iPayloadLen = 0;
        long svId = 0;
        long how = 0;
        long lSftmp = 0;
        StringBuffer receiverMessage = new StringBuffer("");
        String sPayloadLen = "";
        String prnId = "";
        String sSfTmp = "";
        String sSfTmpTmp = "";
        String sSfBin = "";

        ephHeader = new char[]{'0', '2', '3', '1'};
        output = null;
        if (gs.getSocket() != null) {
            sPayloadLen = Utils.charToStringUbl(message, 8, 11);
            try {
                iPayloadLen = Integer.parseInt(sPayloadLen, HEX_BASE);
            } catch (Exception e) {
                numSvInt = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
                output = null;
                return -1;
            }
            LENGTH_EPH_SV = iPayloadLen;
            // Log.e(TAG, "uBlox |iPayloadLen " + iPayloadLen);
            msglength = LENGTH_EPH_SV + LENGTH_CHKSUM;
            byte[] eph = new byte[msglength];

            msgEphLen = msglength * 2;
            msgEph = new char[msgEphLen];
            msgEph = Utils.toHexCharArray(eph);

            char[] checkHeader = new char[]{message[4], message[5], message[6], message[7]};

            boolean blnResult = Arrays.equals(ephHeader, checkHeader);
            if (blnResult) {
                receiverMessage.append(Utils.toHex(eph));
                int msgLen = (LENGTH_HEADER + msglength) * 2;
                output = new char[msgLen];
                System.arraycopy(message, 0, output, 0, msgLen);
            } else {
                output = null;
                Log.d(TAG, "uBlox | Msg could not be identified.");
            }
        } else {
            Log.e(TAG, "uBlox | Wrong parsing attempt.");
            return 3;
        }

        // Log.e(TAG, "uBlox |output parseEphSV:" + String.valueOf(output));

        if (output == null) {
            return -1;
        }
        String mT = Utils.charToString(output, 0, 7);

        String sSvId = Utils.charToStringUbl(output, h + 0, h + 7);
        try {
            svId = Long.parseLong(sSvId, HEX_BASE);
        } catch (Exception e) {
            svId = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
        }

        String sHow = Utils.charToStringUbl(output, h + 8, h + 15);
        try {
            how = Long.parseLong(sHow, HEX_BASE);
        } catch (Exception e) {
            how = 0; // Log.e(TAG, "EDAM | " + e.getMessage());
        }

        if (iPayloadLen > 10) {
            for( int sf = 1; sf < 4; sf++ ) {
                sSf[sf] = "";
                for( int i = 0; i < 8; i++ ) {
                    sSfTmpTmp = Utils.charToStringUbl(output, (h + 16 + (sf - 1) * 64 + i * 8), (h + 23 + (sf - 1) * 64 + i * 8));
                    sSfTmp = sSfTmp + sSfTmpTmp; // complete message as string
                    try {
                        lSftmp = Long.parseLong(sSfTmp, HEX_BASE);
                    } catch (Exception e) {
                        svId = 0;
                        Log.e(TAG, "EDAM | " + e.getMessage());
                        return -1;
                    }
                    sSfBin = Long.toBinaryString(lSftmp);
                    lSftmp = 0;
                    sSfTmp = "";
                    sSfTmpTmp = "";
                    while( sSfBin.length() < 32 ) {
                        sSfBin = "0" + sSfBin;
                    }
                    sSf[sf] = sSf[sf] + sSfBin;
                    sSfBin = "";
                }
            }

            StringBuffer zeroBits = new StringBuffer();
            for( int zero = 0; zero < 60; zero++ ) {
                zeroBits.append('0');
            }

            for( int sf = 1; sf < 4; sf++ ) {
                String sSf_ = "";
                int count = 0;
                for( int in = 0; in < 256; in++ ) {
                    if (in == (count * 32)) {
                        sSf_ = sSf_ + sSf[sf].substring((in + 8), (in + 32)) + "000000";
                        count++;
                    }
                }

                sSf[sf] = sSf_;
                sSf[sf] = zeroBits + sSf[sf];
            }

            if (svId <= 9)
                prnId = '0' + String.valueOf(svId);
            else
                prnId = String.valueOf(svId);

            ephemSubFrame = prnId + sSf[1] + sSf[2] + sSf[3];
            setEphemerisData();
            Log.d(TAG, "ephemSubFrame Data:" + ephemSubFrame);
            if (GlobalState.getisLogFile() == 1)
                log.logEgnosToSdCard(svId + ", " + how, "\n" + ephemSubFrame);
            else
                Log.e(TAG, "uBlox | Unable to create log file");
        } else {
            if (GlobalState.getisLogFile() == 1)
                log.logEgnosToSdCard(svId + ", " + how + "", "No data");
            else
                Log.e(TAG, "uBlox | Unable to create log file");
        }

        return 1;
    }

    /**
    * setEphemerisData  function 
    * The function stores the Ephemeris Data in a 12 X 4 table.
    **/
    public static void setEphemerisData() {
        String prnid = ephemSubFrame.substring(0, 2);
        String ephemPrn;
        boolean prnCheck = false;

        if (ephemData[0] != null) {
            for( int i = 0; i < ephemData.length; i++ ) {
                if (ephemData[i] != null) {
                    ephemPrn = ephemData[i].substring(0, 2);
                    if (ephemPrn.equals(prnid)) {
                        ephemData[i] = ephemSubFrame;
                        prnCheck = true;
                    }
                }
            }
            if (prnCheck == false)
                ephemData[countEphem] = ephemSubFrame;
        } else

            ephemData[countEphem] = ephemSubFrame;
        countEphem++;
    }

    /**
     * displayMessage function 
     * Display any message to a UI thread.
     * 
     * @param message     Messages to display.
     **/
    public static void displayMessage( final int message ) {
        Message msg = messageHandler.obtainMessage(BluetoothReceiverList.uBLOX_MESSAGE);
        Bundle bundle = new Bundle();
        bundle.putInt(BluetoothReceiverList.TOAST, message);
        msg.setData(bundle);
        messageHandler.sendMessage(msg);
    }
}